package com.bifrost.service.impl;

import com.bifrost.common.base.ServerResponse;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.CouponAuthStatus;
import com.bifrost.constant.CouponReleaseMode;
import com.bifrost.constant.CouponStatus;
import com.bifrost.constant.CouponTypeEnum;
import com.bifrost.constant.ValidityType;
import com.bifrost.entity.*;
import com.bifrost.entity.Order;
import com.bifrost.jpa.DynamicQuery;
import com.bifrost.model.coupon.WXCouponDetailRO;
import com.bifrost.model.coupon.WXCouponDetailVO;
import com.bifrost.model.coupon.WXCouponTotalRO;
import com.bifrost.model.coupon.WXCouponTotalVO;
import com.bifrost.model.ro.coupon.CouponDetailFilterRO;
import com.bifrost.model.ro.coupon.CouponFilterRO;
import com.bifrost.model.ro.coupon.CouponRO;
import com.bifrost.model.ro.coupon.CouponTypeRO;
import com.bifrost.model.vo.PageVO;
import com.bifrost.model.vo.coupon.CouponVO;
import com.bifrost.repository.CouponDetailRepository;
import com.bifrost.repository.CouponHistroyRepository;
import com.bifrost.repository.CouponMerchantRepository;
import com.bifrost.repository.CouponRepository;
import com.bifrost.repository.CouponTypeRepository;
import com.bifrost.repository.MediaRepository;
import com.bifrost.repository.MerchantStoreRepository;
import com.bifrost.repository.OrderRepository;
import com.bifrost.repository.OrderReturnRepository;
import com.bifrost.service.AdminCouponService;
import com.bifrost.uid.UidGenerator;
import com.bifrost.util.DateUtils;
import com.bifrost.util.PurchaseOrderCodeUtils;
import com.bifrost.util.TransformUtils;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author rangf
 * @date 2018/5/7
 */
@Service
public class AdminCouponServiceImpl implements AdminCouponService {


    private Logger LOGGER = LoggerFactory.getLogger(AdminCouponServiceImpl.class);

    @Autowired
    CouponTypeRepository couponTypeRepository;
    @Autowired
    CouponRepository couponRepository;
    @Autowired
    CouponMerchantRepository couponMerchantRepository;
    @Autowired
    CouponDetailRepository couponDetailRepository;
    @Autowired
    MediaRepository mediaRepository;
    @Autowired
    OrderRepository orderRepository;
    @Autowired
    OrderReturnRepository orderReturnRepository;
    @Autowired
    MerchantStoreRepository merchantStoreRepository;

    @PersistenceContext
    @Qualifier("entityManager")
    protected EntityManager em;

    @Autowired
    UidGenerator defaultUidGenerator;
    @Autowired
    CouponHistroyRepository couponHistroyRepository;
    @Autowired
    DynamicQuery dynamicQuery;

    /**
     * 添加优惠券类型
     *
     * @param user user
     * @param ro ro
     * @return
     */
    @Override
    public ServerResponse addCouponType(User user, CouponTypeRO ro) {
        CouponType couponType = couponTypeRepository.getByTypeNameOrTypeCode(ro.getTypeCode(), ro.getTypeCode());
        if (null != couponType) {
            CouponType ct = new CouponType();
            BeanUtils.copyProperties(ro, ct);
            ct.setUpdatedBy(user.getAdminName());
            ct.setUpdatedTimestamp(new Date());
            //优惠券与门店不再关联
//            ct.setMerchantStore(user.getMerchantStore());
            couponTypeRepository.save(ct);
        }
        return ServerResponse.createByErrorMsg("该优惠券编码或名称已存在");
    }

    /**
     * 更新优惠券类型
     *
     * @param user user
     * @param ro ro
     * @return
     */
    @Override
    public ServerResponse updateCouponType(User user, CouponTypeRO ro) {
        if (ro.getCouponTypeId() != null) {
            CouponType couponType = couponTypeRepository.findOne(ro.getCouponTypeId());
            if (null != couponType) {
                couponType.setArchived(ro.isArchived());
                couponType.setTypeCode(ro.getTypeCode());
                couponType.setTypeName(ro.getTypeName());
                couponType.setTypeDescription(ro.getTypeDescription());
                couponType.setUpdatedBy(user.getAdminName());
                couponType.setUpdatedTimestamp(new Date());
                couponTypeRepository.save(couponType);
            }
            return ServerResponse.createByErrorMsg("更新成功");
        }
        return ServerResponse.createByErrorMsg("更新失败");
    }

    /**
     * 删除优惠券类型
     *
     * @param couponTypeIds couponTypeIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse deleteCouponType(Long[] couponTypeIds) {
        try {
            for (Long couponTypeId : couponTypeIds) {
                couponTypeRepository.delete(couponTypeId);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("failed to delete couponType");
        }
        return ServerResponse.createBySuccessMsg("删除成功");
    }


    /**
     * 优惠券类型列表
     *
     * @param user user
     * @return
     */
    //优惠券不再与门店关联
    /*
    @Override
    public List<CouponTypeRO> listCouponType(User user) {
        MerchantStore merchantStore = user.getMerchantStore();
        if (merchantStore == null)
            return null;
        List<CouponType> couponTypeList = couponTypeRepository.getAllByMerchantStore(merchantStore);
        if (CollectionUtils.isEmpty(couponTypeList)) {
            List<CouponTypeRO> roList = new ArrayList<>();
            for (CouponType couponType : couponTypeList) {
                CouponTypeRO ro = new CouponTypeRO();
                BeanUtils.copyProperties(couponType, ro);
                roList.add(ro);
            }
            return roList;
        }
        return null;
    }
    */

    /**
     * 添加优惠券
     *
     * @param user user
     * @param ro ro
     * @return
     */
    @Override
    public ServerResponse addCoupon(User user, CouponRO ro) {
        String msg = validCoupnRO(ro);
        if (StringUtils.isNotEmpty(msg))
            return ServerResponse.createByErrorMsg(msg);
        MerchantStore store = user.getMerchantStore();
        if(store == null){
            Set<MerchantStore> merchantStoreSet = user.getMerchantStores();
            if(CollectionUtils.isEmpty(merchantStoreSet)){
                store = merchantStoreRepository.findAll(new PageRequest(0,10)).getContent().get(0);
            }else {
                List<MerchantStore> merchantStoreList = new ArrayList<>(merchantStoreSet);
                store = merchantStoreList.get(0);
            }
        }
        if (store == null)
            return ServerResponse.createByErrorMsg("添加失败");
        Coupon coupon = new Coupon();
        if (CouponTypeEnum.SERVICE_COUPON.name().equalsIgnoreCase(ro.getCouponTypeCode()))
            ro.setRuleCode(null);
        BeanUtils.copyProperties(ro, coupon);
        if(ro.getMediaId() != null){
            Media media = mediaRepository.findOne(ro.getMediaId());
            if(media != null){
                coupon.setMedia(media);
            }
        }
        if(StringUtils.isNotEmpty(ro.getReleaseMode())){
            coupon.setReleaseMode(ro.getReleaseMode());
        }else {
            coupon.setReleaseMode(ro.getReleaseMode());
        }
        //优惠券类型时间段
        coupon.setValidityType(ValidityType.PERIOD);
        //微信券码标志
        coupon.setFlag("87");
        coupon.setReleaseBy(store);
        coupon.setIsRefundable(ro.isRefundable());
        coupon.setUpdatedTimestamp(new Date());
        coupon.setUpdatedBy(user.getAdminName());
        coupon.setQuantityAvailable(coupon.getCouponQuantity());
        Coupon dbCoupon = couponRepository.save(coupon);
        /*
         * 保存优惠券发放门店信息
         */
        CouponMerchant couponMerchant = new CouponMerchant();
        couponMerchant.setCoupon(dbCoupon);
        couponMerchant.setMerchantStore(store);
        couponMerchantRepository.save(couponMerchant);
        return ServerResponse.createBySuccessMsg("添加成功");
    }

    /**
     * 优惠券审核通过：批量
     *
     * @param user user
     * @param couponIds couponIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse authBatchCoupon(User user, Long[] couponIds) {
        List<Long> couponIdList = Arrays.asList(couponIds);
        for (Long couponId : couponIdList) {
            Coupon coupon = couponRepository.findOne(couponId);
            if (coupon == null)
                throw new RuntimeException("failed to auth coupon for the reasons not find couponId:" + couponId);
            if (CouponAuthStatus.AUTHED.equalsIgnoreCase(coupon.getAuthStatus()))
                throw new RuntimeException("failed to auth coupon for the reasons couponId has authed:" + couponId);
            else if (CouponAuthStatus.UNAUTH.equalsIgnoreCase(coupon.getAuthStatus())) {
                coupon.setAuthStatus(CouponAuthStatus.AUTHED);
                coupon.setUpdatedBy(user.getAdminName());
                coupon.setUpdatedTimestamp(new Date());
            } else
                throw new RuntimeException("coupon authStatus has error for couponId:" + couponId);
        }
        return ServerResponse.createBySuccessMsg("审核成功");
    }

    /**
     * 优惠券审核
     *
     * @param user user
     * @param couponId couponId
     * @param authType authType
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse auth(User user, Long couponId, String authType) {
        Coupon coupon = couponRepository.findOne(couponId);
        if (coupon == null)
            return ServerResponse.createByErrorMsg("审核失败");
        //审核操作时
        if (CouponAuthStatus.AUTHED.equalsIgnoreCase(authType) && coupon.getAuthStatus().equals(CouponAuthStatus.AUTHED))
            return ServerResponse.createByErrorMsg("该优惠券已审核");
        //下架操作时
        if(CouponAuthStatus.SOLD_OUT.equalsIgnoreCase(authType) && CouponAuthStatus.SOLD_OUT.equalsIgnoreCase(coupon.getAuthStatus())){
            return ServerResponse.createByErrorMsg("该优惠券已下架");
        }
        coupon.setAuthStatus(authType);
        coupon.setUpdatedBy(user.getAdminName());
        coupon.setUpdatedTimestamp(new Date());
        Coupon couponFresh = couponRepository.save(coupon);
        //if(CouponAuthStatus.AUTHED.equals(couponFresh.getAuthStatus())) {
            //优惠券明细支付成功后生成
            //autoGenerateCouponDetail(couponFresh.getCouponId());
            return ServerResponse.createBySuccessMsg("已通过");
//        }
//        else
//            return ServerResponse.createBySuccessMsg("已驳回");
    }

    protected String validCoupnRO(CouponRO ro) {
        String couponTypeCode = ro.getCouponTypeCode();
        if (!CouponTypeEnum.CASH_COUPON.name().equalsIgnoreCase(couponTypeCode) &&
                !CouponTypeEnum.SERVICE_COUPON.name().equalsIgnoreCase(couponTypeCode)
                &&!CouponTypeEnum.OFFLINE_COUPON.name().equalsIgnoreCase(couponTypeCode))
            return "优惠券类型错误";
        if (CouponTypeEnum.CASH_COUPON.name().equalsIgnoreCase(couponTypeCode) || CouponTypeEnum.OFFLINE_COUPON.name().equalsIgnoreCase(couponTypeCode))
            if (StringUtils.isEmpty(ro.getRuleCode()))
                return "现金券/线下券需要填写富机规则码";
        Date asd = ro.getActiveStartDate();
        Date aed = ro.getActiveEndDate();
        Date rsd = ro.getReleaseDateStart();
        Date red = ro.getReleaseDateEnd();
        if (asd.after(aed))
            return "生效起止日期错误";
        if (rsd.after(red))
            return "发放起止日期错误";
        if (rsd.after(asd))
            return "发放开始日期必须在生效日期之前";
        // 取消该验证
//        if (ro.getOrderMinTotal().compareTo(ro.getDiscountAmount()) < 0)
//            return "订单最低金额必须大于折扣金额";
        return null;
    }

    /**
     * 更新优惠券
     *
     * @param user user
     * @param ro ro
     * @return
     */
    @Override
    public ServerResponse updateCoupon(User user, CouponRO ro) {
        String msg = validCoupnRO(ro);
        if (StringUtils.isNotEmpty(msg))
            return ServerResponse.createByErrorMsg(msg);
        Long couponId = ro.getCouponId();
        if (couponId == null)
            return ServerResponse.createByErrorMsg("更新失败");
        Coupon coupon = couponRepository.findOne(couponId);
        if (coupon == null)
            return ServerResponse.createByErrorMsg("更新失败");
        if(CouponAuthStatus.AUTHED.equalsIgnoreCase(coupon.getAuthStatus()))
            ServerResponse.createByErrorMsg("优惠券已审核不能修改");
        if(CouponAuthStatus.SOLD_OUT.equalsIgnoreCase(coupon.getAuthStatus())){
            ServerResponse.createByErrorMsg("优惠券已下架不能修改");
        }
        if(CouponTypeEnum.SERVICE_COUPON.name().equalsIgnoreCase(ro.getCouponTypeCode()))
            ro.setRuleCode(null);
        if(CouponAuthStatus.REJECT.equalsIgnoreCase(coupon.getAuthStatus()))
            coupon.setAuthStatus(CouponAuthStatus.UNAUTH);
        BeanUtils.copyProperties(ro, coupon);
        Media media = mediaRepository.findOne(ro.getMediaId());
        if(media != null){
            coupon.setMedia(media);
        }
        coupon.setIsRefundable(ro.isRefundable());
        coupon.setUpdatedTimestamp(new Date());
        coupon.setUpdatedBy(user.getAdminName());
        coupon.setQuantityAvailable(coupon.getCouponQuantity());
        couponRepository.save(coupon);
        return ServerResponse.createBySuccessMsg("更新成功");
    }

    /**
     * 删除优惠券
     *
     * @param couponIds couponIds
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse deleteCoupon(Long[] couponIds) {
        List<Long> couponIdList = Arrays.asList(couponIds);
        for (Long couponId : couponIdList) {
            Coupon coupon = couponRepository.findOne(couponId);
            if (coupon == null)
                throw new RuntimeException("coupon is null for couponId:" + couponId);
            /*
            CouponMerchant couponMerchant = couponMerchantRepository.getByCouponAndMerchantStore(coupon, coupon.getReleaseBy());
            if (couponMerchant == null)
                throw new RuntimeException("couponMerchant is null for couponId:" + couponId);
                */
            //couponMerchantRepository.delete(couponMerchant.getId());
            couponRepository.delete(couponId);
        }
        return ServerResponse.createBySuccessMsg("删除成功");
    }

    /**
     * 优惠券列表
     *
     * @param merchantStore merchantStore
     * @param ro ro
     * @param merchantStoreIdList
     * @return
     */
    @Override
    public PageVO<CouponVO> listCoupon(MerchantStore merchantStore, CouponFilterRO ro, List<Long> merchantStoreIdList) {
        Pageable pageable = new PageRequest(ro.getPage() - 1, ro.getPageSize(),
                new Sort(Sort.Direction.DESC, "updatedTimestamp"));
        Specification<Coupon> specification = new Specification<Coupon>() {
            @Override
            public Predicate toPredicate(Root<Coupon> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                //predicates.add(cb.equal(root.get("releaseBy"), merchantStore));
                if(CollectionUtils.isNotEmpty(merchantStoreIdList)){
                    CriteriaBuilder.In<Long> in = cb.in(root.get("releaseBy").get("merchantId"));
                    for(Long id : merchantStoreIdList){
                        in.value(id);
                    }
                    predicates.add(in);
                }
                if (StringUtils.isNotEmpty(ro.getCouponTypeCode()))
                    predicates.add(cb.equal(root.get("couponTypeCode"), ro.getCouponTypeCode()));
                if (StringUtils.isNotEmpty(ro.getAuthStatus()))
                    predicates.add(cb.equal(root.get("authStatus"), ro.getAuthStatus()));
                Date activeStartDate = ro.getActiveStartDate();
                Date activeEndDate = ro.getActiveEndDate();
                Path<Date> asd = root.get("activeStartDate");
                Path<Date> aed = root.get("activeEndDate");
                if (null != activeStartDate && null == activeEndDate)
                    predicates.add(cb.greaterThanOrEqualTo(asd, activeStartDate));
                if (null == activeStartDate && null != activeEndDate)
                    predicates.add(cb.lessThanOrEqualTo(aed, activeEndDate));
                if (null != activeStartDate && null != activeEndDate) {
                    predicates.add(cb.greaterThanOrEqualTo(asd, activeStartDate));
                    predicates.add(cb.lessThanOrEqualTo(aed, activeEndDate));
                }
                Date releaseDateStart = ro.getReleaseDateStart();
                Date releaseDateEnd = ro.getReleaseDateEnd();
                Path<Date> rsd = root.get("releaseDateStart");
                Path<Date> red = root.get("releaseDateStart");
                if (null != releaseDateStart && null == releaseDateEnd)
                    predicates.add(cb.greaterThanOrEqualTo(rsd, releaseDateStart));
                if (null == releaseDateStart && null != releaseDateEnd)
                    predicates.add(cb.lessThanOrEqualTo(red, releaseDateEnd));
                if (null != releaseDateStart && null != releaseDateEnd) {
                    predicates.add(cb.greaterThanOrEqualTo(rsd, releaseDateStart));
                    predicates.add(cb.lessThanOrEqualTo(red, releaseDateEnd));
                }
                if(StringUtils.isNotEmpty(ro.getCouponName())){
                    predicates.add(cb.like(root.get("couponName"),"%"+ro.getCouponName().trim()+"%"));
                }
                if(StringUtils.isNotEmpty(ro.getReleaseMode())){
                    predicates.add(cb.equal(root.get("releaseMode"),ro.getReleaseMode()));
                }
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page<Coupon> data = couponRepository.findAll(specification, pageable);
        if (null != data && data.hasContent()) {
            List<Coupon> couponList = data.getContent();
            if (CollectionUtils.isNotEmpty(couponList)) {
                List<CouponVO> couponVOList = new ArrayList<>();
                for (Coupon coupon : couponList) {
                    CouponVO vo = new CouponVO();
                    BeanUtils.copyProperties(coupon, vo);
                    vo.setRefundable(coupon.getIsRefundable());
                    vo.setEnabled(coupon.getIsEnabled());
                    Media media = coupon.getMedia();
                    if(media != null){
                        vo.setCouponImg(HttpRequestUtils.getUrlAccessPath() + coupon.getMedia().getUrl());
                        vo.setMediaId(coupon.getMedia().getMediaId());
                    }
                    couponVOList.add(vo);
                }
                return new PageVO<>(ro.getPage(), ro.getPageSize(), (int) data.getTotalElements(), couponVOList);
            }
        }
        return null;
    }

    /**
     * 优惠券明细
     *
     * @param ro ro
     * @return
     */
    @Override
    public Page<CouponDetail> listCouponDetail(CouponDetailFilterRO ro) {
        Coupon coupon = couponRepository.findOne(ro.getCouponId());
        if (coupon != null) {
            Pageable pageable = new PageRequest(ro.getPage() - 1, ro.getPageSize(),
                    new Sort(Sort.Direction.ASC, "couponDetailId"));
            Specification<CouponDetail> specification = new Specification<CouponDetail>() {
                @Override
                public Predicate toPredicate(Root<CouponDetail> r, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                    List<Predicate> predicates = new ArrayList<>();
                    predicates.add(cb.equal(r.get("coupon"), coupon));
                    if (ro.getUsed() != null)
                        predicates.add(cb.equal(r.get("isUsed"), ro.getUsed()));
                    if (StringUtils.isNotEmpty(ro.getCouponStatus()))
                        predicates.add(cb.equal(r.get("couponStatus"), ro.getCouponStatus()));
                    Join<CouponDetail,Customer> join = r.join("customer",JoinType.INNER);
                    if(StringUtils.isNotEmpty(ro.getCardNo())){
                        predicates.add(cb.like(join.get("loyaltyCard"),"%"+ ro.getCardNo().trim() +"%"));
                    }
                    if(StringUtils.isNotEmpty(ro.getPhoneNo())){
                        predicates.add(cb.like(join.get("customerPhone"),"%"+ ro.getPhoneNo().trim() +"%"));
                    }
                    // 添加优惠券编码查询条件
                    if (StringUtils.isNotEmpty(ro.getCouponCode()))
                        predicates.add(cb.equal(r.get("couponCode"), ro.getCouponCode()));
                    Predicate[] p = new Predicate[predicates.size()];
                    return cb.and(predicates.toArray(p));
                }
            };
            return couponDetailRepository.findAll(specification, pageable);
        }
        return null;
    }

    /**
     * 自动生成优惠券明细
     *
     * @param couponId authed coupon
     */
    @Override
    public void autoGenerateCouponDetail(Long couponId) {
        Coupon c = couponRepository.findOne(couponId);
        if(c != null) {
            Integer quantity = c.getCouponQuantity();
            if(quantity != null && quantity >= 1){
                //MerchantStore merchantStore = c.getReleaseBy();
                List<CouponDetail> couponDetailList = new ArrayList<>();
                for (int i = 0; i < quantity; i++){
                    CouponDetail cd = new CouponDetail();
                    cd.setCoupon(c);
                    cd.setCouponName(c.getCouponName());
                    cd.setCouponTypeCode(c.getCouponTypeCode());
                    cd.setCouponDescription(c.getCouponDescription());
                    cd.setRelatedTargetQuantity(c.getRelatedTargetQuantity());
                    cd.setMaxUsesPerCustomer(c.getMaxUsesPerCustomer());
                    //cd.setMerchantId(merchantStore.getMerchantId());
                    cd.setOrderMinTotal(c.getOrderMinTotal());
                    cd.setDiscountAmount(c.getDiscountAmount());
                    cd.setReleaseDateStart(c.getReleaseDateStart());
                    cd.setReleaseDateEnd(c.getReleaseDateEnd());
                    cd.setActiveStartDate(c.getActiveStartDate());
                    cd.setActiveEndDate(c.getActiveEndDate());
                    //cd.setCouponCode(defaultUidGenerator.getUID());
                    cd.setCouponStatus(CouponStatus.UNUSED);
                    cd.setIsUsed(Boolean.FALSE);
                    //cd.setReleaseBy(merchantStore);
                    cd.setValidityType(ValidityType.DAYS);
                    cd.setAddTime(null);
                    couponDetailList.add(cd);
                }
                if (CollectionUtils.isNotEmpty(couponDetailList)) {
                    for(int i = 0; i < couponDetailList.size(); i++) {
                        em.persist(couponDetailList.get(i));
                        //生成劵码
                        String code= PurchaseOrderCodeUtils.addCouponCode(couponDetailList.get(i).getCouponDetailId().toString(),10,Boolean.FALSE);
                        couponDetailList.get(i).setCouponCode(Long.parseLong(code));
                        if(i % 30== 0) {
                            em.flush();
                            em.clear();
                        }
                    }
                }
                return;
            }
            LOGGER.error("coupon quantity has error for couponId:" + couponId);
            return;
        }
        LOGGER.error("autoGenerateCouponDetail failed for error couponId:" + couponId);
        return;
    }

    /**
     * 微信券明细展示
     * @param ro
     * @param merchantStoreIdList
     * @param exportFlag
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageVO listWXCouponDetail(WXCouponDetailRO ro, List<Long> merchantStoreIdList, boolean exportFlag) {
        long startTime = System.currentTimeMillis();    //获取开始时间
        List<WXCouponDetailVO> wxCouponDetailVOList = getWXCouponDetailVOList(ro,merchantStoreIdList,exportFlag);
        String newSql = "select FOUND_ROWS();";
        int count = 0;
        List<List<Object>> l = dynamicQuery.nativeQueryList(newSql, true);
        for(List list : l){
            count = Integer.parseInt(String.valueOf(list.get(0)));
        }
        PageVO<WXCouponDetailVO> pageVO = new PageVO(ro.getPageCode(),ro.getPageSize(),count,wxCouponDetailVOList);
        long endTime = System.currentTimeMillis();    //获取结束时间
        LOGGER.info("微信券售卖明细运行耗时：" + (endTime - startTime) + "ms");    //输出程序运行时间
        return pageVO;
    }

    private List<WXCouponDetailVO> getWXCouponDetailVOList(WXCouponDetailRO ro, List<Long> merchantStoreIdList, boolean exportFlag) {
        StringBuilder sql = new StringBuilder("SELECT SQL_CALC_FOUND_ROWS ch.MODIFY_DATE,ms.STORE_CODE,ms.STORE_NAME,cd.RELEASE_MODE,cd.COUPON_ID,cd.COUPON_NAME,c.LOYALTY_CARD,c.CUSTOMER_PHONE,IFNULL(cd.DISCOUNT_AMOUNT,0),ch.OPERATION,IFNULL(cd.PRICE,0),IFNULL(cd.BONUS_POINTS,0),cd.COUPON_CODE\n" +
                "FROM COUPON_DETAIL CD\n" +
                "inner join coupon_histroy ch on ch.COUPON_DETAIL_ID = cd.COUPON_DETAIL_ID\n" +
                "left join customer c on c.CUSTOMER_ID = ch.CUSTOMER_ID\n" +
                "left join merchant_store ms on ms.MERCHANT_ID = cd.RELEASE_BY\n");
        sql.append("where cd.RELEASE_BY in ("+ StringUtils.join(merchantStoreIdList,",")+")\n");
        //只查询购买和退还的记录
        sql.append("and ch.OPERATION in ('NEW','RETURN') \n");
        if(StringUtils.isNotEmpty(ro.getLoyaltyCard())){
            sql.append("and c.LOYALTY_CARD like ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getCustomerPhone())){
            sql.append("and c.CUSTOMER_PHONE like ? \n");
        }
        if(null != ro.getCouponId()){
            sql.append("and cd.COUPON_ID = ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getStartDate())){
            sql.append("and ch.MODIFY_DATE >= ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getEndDate())){
            sql.append("and ch.MODIFY_DATE <= ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getCouponTypeCode())){
            sql.append("and cp.RELEASE_MODE = ? \n");
        }
        sql.append("ORDER BY cd.COUPON_ID DESC \n");
        if(!exportFlag) {
            sql.append("limit ?,?");
        }
        List<List<Object>> resultList = dynamicQuery.nativeQueryList(
                String.valueOf(sql),
                Boolean.valueOf(true),
                ro.getCouponId(),//查询条件，优惠券id
                StringUtils.isNotEmpty(ro.getLoyaltyCard()) ? "%"+ro.getLoyaltyCard()+"%" : null,
                StringUtils.isNotEmpty(ro.getCustomerPhone()) ? "%"+ro.getCustomerPhone()+"%" : null,
                StringUtils.isNotEmpty(ro.getStartDate()) ? DateUtils.parse(ro.getStartDate(),DateUtils.DEFAULT_DATE_FORMAT):null,
                StringUtils.isNotEmpty(ro.getEndDate()) ? DateUtils.parse(ro.getEndDate(),DateUtils.DEFAULT_DATE_FORMAT):null,
                StringUtils.isNotEmpty(ro.getCouponTypeCode()) ? ro.getCouponTypeCode() : null,
                exportFlag ? null : (ro.getPageCode()-1)*ro.getPageSize(),
                exportFlag ? null : ro.getPageSize());
        List<WXCouponDetailVO> wxCouponDetailVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(resultList)){
            resultList.forEach(list -> {
                WXCouponDetailVO wxCouponDetailVO = new WXCouponDetailVO();
                int index = 0;
                //优惠券购买/退还时间
                wxCouponDetailVO.setGeneratedTime(String.valueOf(list.get(index++)));
                //优惠券门店信息
                wxCouponDetailVO.setMerchantCode(String.valueOf(list.get(index++)));
                wxCouponDetailVO.setMerchantName(String.valueOf(list.get(index++)));
                //优惠券类型
                String type = String.valueOf(list.get(index++));
                wxCouponDetailVO.setCouponTypeCode(TransformUtils.mapToReleaseModeCN(type));
                wxCouponDetailVO.setCouponId(String.valueOf(list.get(index++)));
                wxCouponDetailVO.setCouponName(String.valueOf(list.get(index++)));
                wxCouponDetailVO.setCustomerCardNum(String.valueOf(list.get(index++)));
                wxCouponDetailVO.setCustomerPhone(String.valueOf(list.get(index++)));
                String discountAmount = String.valueOf(list.get(index++));
                //取优惠券购买还是退券标志
                String operation = String.valueOf(list.get(index++));
                //购买
                if(CouponHistroy.Operation.NEW.name().equalsIgnoreCase(operation)){
                    wxCouponDetailVO.setDiscountAmount(discountAmount);
                    wxCouponDetailVO.setBuyOrReturn("购券");
                    if(CouponReleaseMode.CASH_PURCHASE.equalsIgnoreCase(type)){
                        wxCouponDetailVO.setCouponPrice(String.valueOf(list.get(index ++)));
                        index ++;
                    }else {
                        index ++;
                        wxCouponDetailVO.setCouponPrice(String.valueOf(list.get(index ++)));
                    }
                }else{
                    wxCouponDetailVO.setDiscountAmount("-" + discountAmount);
                    wxCouponDetailVO.setBuyOrReturn("退券");
                    if(CouponReleaseMode.CASH_PURCHASE.equalsIgnoreCase(type)){
                        wxCouponDetailVO.setCouponPrice("-" + String.valueOf(list.get(index ++)));
                        index ++;
                    }else {
                        index ++;
                        wxCouponDetailVO.setCouponPrice("-" + String.valueOf(list.get(index ++)));
                    }
                }
                wxCouponDetailVO.setCouponCode(String.valueOf(list.get(index ++)));
                wxCouponDetailVOList.add(wxCouponDetailVO);
            });
        }
        return wxCouponDetailVOList;
    }

    /**
     * 微信券售卖汇总
     * @param ro
     * @param merchantStoreIdList
     * @param exportFlag
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageVO<WXCouponTotalVO> listWXCouponTotal(WXCouponTotalRO ro, List<Long> merchantStoreIdList, boolean exportFlag) {
        long startTime = System.currentTimeMillis();    //获取开始时间
        List<WXCouponTotalVO> wxCouponTotalVOList = getWXCouponTotalVOList(ro,merchantStoreIdList,exportFlag);
        String newSql = "select FOUND_ROWS();";
        int count = 0;
        List<List<Object>> l = dynamicQuery.nativeQueryList(newSql, true);
        for(List list : l){
            count = Integer.parseInt(String.valueOf(list.get(0)));
        }
        PageVO<WXCouponTotalVO> pageVO = new PageVO(ro.getPageCode(),ro.getPageSize(),count,wxCouponTotalVOList);
        long endTime = System.currentTimeMillis();    //获取结束时间
        LOGGER.info("微信券售卖汇总报表耗时：" + (endTime - startTime) + "ms");    //输出程序运行时间
        return pageVO;
    }

    @Override
    public List<WXCouponTotalVO> exportWXCouponTotal(WXCouponTotalRO ro, List<Long> merchantStoreIdList) {
        List<WXCouponTotalVO> wxCouponTotalVOList = getWXCouponTotalVOList(ro,merchantStoreIdList,Boolean.TRUE);
        return wxCouponTotalVOList;
    }

    @Override
    public List<WXCouponDetailVO> exportWXCouponDetail(WXCouponDetailRO ro, List<Long> merchantStoreIdList) {
        List<WXCouponDetailVO> wxCouponDetailVOList = getWXCouponDetailVOList(ro,merchantStoreIdList,Boolean.TRUE);
        return wxCouponDetailVOList;
    }

    private List<WXCouponTotalVO> getWXCouponTotalVOList(WXCouponTotalRO ro, List<Long> merchantStoreIdList, Boolean exportFlag) {
        StringBuilder sql = new StringBuilder("SELECT SQL_CALC_FOUND_ROWS ms.STORE_CODE,ms.STORE_NAME,cp.RELEASE_MODE,cp.COUPON_ID,cp.COUPON_NAME,IFNULL(cp.DISCOUNT_AMOUNT,0),IFNULL(cp.PRICE,0),IFNULL(cp.BONUS_POINTS,0),sum(case when ch.OPERATION = 'NEW' then 1 when ch.OPERATION = 'RETURN' then -1 end)\n" +
                "FROM coupon cp \n" +
                "inner join coupon_detail cd on cp.COUPON_ID = cd.COUPON_ID\n" +
                "inner join coupon_histroy ch on ch.COUPON_DETAIL_ID = cd.COUPON_DETAIL_ID\n" +
                "left join merchant_store ms on cp.RELEASE_BY = ms.MERCHANT_ID \n");
        sql.append("where cd.RELEASE_BY in ("+ StringUtils.join(merchantStoreIdList,",")+")\n");
        //只查询购买和退还的记录
        sql.append("and ch.OPERATION in ('NEW','RETURN') \n");
        if( null != ro.getCouponId()){
            sql.append("and cp.COUPON_ID = ?\n");
        }
        if(StringUtils.isNotEmpty(ro.getStartDate())){
            sql.append("and ch.MODIFY_DATE >= ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getEndDate())){
            sql.append("and ch.MODIFY_DATE <= ? \n");
        }
        if(StringUtils.isNotEmpty(ro.getCouponTypeCode())){
            sql.append("and cp.RELEASE_MODE = ? \n");
        }
        sql.append("GROUP BY cp.COUPON_ID \n");
        sql.append("ORDER BY cd.COUPON_ID DESC\n");
        if(!exportFlag) {
            sql.append("limit ?,?");
        }
        List<List<Object>> resultList = dynamicQuery.nativeQueryList(
                String.valueOf(sql),
                Boolean.valueOf(true),
                ro.getCouponId(),//查询条件，优惠券id
                StringUtils.isNotEmpty(ro.getStartDate()) ? DateUtils.parse(ro.getStartDate(),DateUtils.DEFAULT_DATE_FORMAT):null,
                StringUtils.isNotEmpty(ro.getEndDate()) ? DateUtils.parse(ro.getEndDate(),DateUtils.DEFAULT_DATE_FORMAT):null,
                StringUtils.isNotEmpty(ro.getCouponTypeCode()) ? ro.getCouponTypeCode() : null,
                exportFlag ? null : (ro.getPageCode()-1)*ro.getPageSize(),
                exportFlag ? null : ro.getPageSize());
        List<WXCouponTotalVO> wxCouponTotalVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(resultList)){
            resultList.forEach(list -> {
                WXCouponTotalVO wxCouponTotalVO = new WXCouponTotalVO();
                int index = 0;
                //优惠券门店信息
                wxCouponTotalVO.setMerchantCode(String.valueOf(list.get(index++)));
                wxCouponTotalVO.setMerchantName(String.valueOf(list.get(index++)));
                //优惠券类型
                String type = String.valueOf(list.get(index++));
                wxCouponTotalVO.setCouponTypeCode(TransformUtils.mapToReleaseModeCN(type));
                wxCouponTotalVO.setCouponId(String.valueOf(list.get(index++)));
                wxCouponTotalVO.setCouponName(String.valueOf(list.get(index++)));
                BigDecimal paymentAmount = BigDecimal.valueOf(Double.valueOf(String.valueOf(list.get(index ++))));
                //取优惠券购买还是退券标志
                BigDecimal price;
                if(CouponReleaseMode.CASH_PURCHASE.equalsIgnoreCase(type)){
                    price = BigDecimal.valueOf(Double.valueOf(String.valueOf(list.get(index ++))));
                    index ++;
                }else {
                    index ++;
                    price = BigDecimal.valueOf(Double.valueOf(String.valueOf(list.get(index ++))));
                }
                BigDecimal quantity = BigDecimal.valueOf(Double.valueOf(String.valueOf(list.get(index ++))));
                wxCouponTotalVO.setPaymentAmount(String.valueOf(paymentAmount.multiply(quantity).setScale(2)));
                wxCouponTotalVO.setCouponPrice(String.valueOf(price.multiply(quantity).setScale(2)));
                wxCouponTotalVO.setSaleQuantity(String.valueOf(quantity.setScale(0)));
                wxCouponTotalVOList.add(wxCouponTotalVO);
            });
        }
        return wxCouponTotalVOList;
    }


}
